package com.xyy.service.impl;

import com.xyy.config.MinioConfig;
import com.xyy.service.FileService;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * 文件服务实现类 - MinIO版本
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig minioConfig;

    @Override
    public String uploadAvatar(MultipartFile file) {
        try {
            // 检查文件类型
            if (!isValidImage(file)) {
                throw new IllegalArgumentException("不支持的文件类型，请上传图片文件");
            }

            // 检查文件大小 (限制为5MB)
            if (file.getSize() > 5 * 1024 * 1024) {
                throw new IllegalArgumentException("文件大小不能超过5MB");
            }

            // 生成唯一文件名
            String originalFilename = file.getOriginalFilename();
            String extension = getFileExtension(originalFilename);
            String fileName = "avatars/" + UUID.randomUUID().toString() + extension;

            // 确保存储桶存在
            ensureBucketExists();

            // 上传文件到MinIO
            try (InputStream inputStream = file.getInputStream()) {
                minioClient.putObject(
                    PutObjectArgs.builder()
                        .bucket(minioConfig.getBucket())
                        .object(fileName)
                        .stream(inputStream, file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build()
                );
            }

            // 生成预签名URL，有效期7天
            String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(minioConfig.getBucket())
                    .object(fileName)
                    .expiry(7, java.util.concurrent.TimeUnit.DAYS)
                    .build()
            );

            // 返回预签名URL
            return presignedUrl;

        } catch (Exception e) {
            log.error("上传头像到MinIO失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    @Override
    public void deleteAvatar(String fileName) {
        try {
            // 从URL中提取对象名
            String objectName = extractObjectNameFromUrl(fileName);
            
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(minioConfig.getBucket())
                    .object(objectName)
                    .build()
            );
            log.info("成功删除头像文件: {}", objectName);
        } catch (Exception e) {
            log.error("删除头像文件失败: {}", fileName, e);
        }
    }

    @Override
    public boolean isValidImage(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return false;
        }

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            return false;
        }

        String contentType = file.getContentType();
        if (contentType == null) {
            return false;
        }

        // 检查文件扩展名
        String[] allowedExtensions = {".jpg", ".jpeg", ".png", ".gif", ".bmp"};
        String lowerFilename = originalFilename.toLowerCase();
        boolean hasValidExtension = false;
        for (String ext : allowedExtensions) {
            if (lowerFilename.endsWith(ext)) {
                hasValidExtension = true;
                break;
            }
        }

        // 检查MIME类型
        boolean hasValidMimeType = contentType.startsWith("image/");

        return hasValidExtension && hasValidMimeType;
    }

    @Override
    public String uploadFile(byte[] fileBytes, String filename, String folder) {
        try {
            // 检查文件大小 (限制为10MB)
            if (fileBytes.length > 10 * 1024 * 1024) {
                throw new IllegalArgumentException("文件大小不能超过10MB");
            }

            // 生成唯一文件名
            String extension = getFileExtension(filename);
            String fileName = folder + "/" + UUID.randomUUID().toString() + extension;

            // 确保存储桶存在
            ensureBucketExists();

            // 上传文件到MinIO
            try (InputStream inputStream = new java.io.ByteArrayInputStream(fileBytes)) {
                minioClient.putObject(
                    PutObjectArgs.builder()
                        .bucket(minioConfig.getBucket())
                        .object(fileName)
                        .stream(inputStream, fileBytes.length, -1)
                        .contentType(getContentType(extension))
                        .build()
                );
            }

            // 生成预签名URL，有效期7天
            String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(minioConfig.getBucket())
                    .object(fileName)
                    .expiry(7, java.util.concurrent.TimeUnit.DAYS)
                    .build()
            );

            // 返回预签名URL
            return presignedUrl;

        } catch (Exception e) {
            log.error("上传文件到MinIO失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    @Override
    public String uploadCover(MultipartFile file) {
        try {
            // 检查文件类型
            if (!isValidImage(file)) {
                throw new IllegalArgumentException("不支持的文件类型，请上传图片文件");
            }

            // 检查文件大小 (限制为5MB)
            if (file.getSize() > 5 * 1024 * 1024) {
                throw new IllegalArgumentException("文件大小不能超过5MB");
            }

            // 生成唯一文件名
            String originalFilename = file.getOriginalFilename();
            String extension = getFileExtension(originalFilename);
            String fileName = "covers/" + UUID.randomUUID().toString() + extension;

            // 确保封面存储桶存在
            ensureCoverBucketExists();

            // 上传文件到MinIO
            try (InputStream inputStream = file.getInputStream()) {
                minioClient.putObject(
                    PutObjectArgs.builder()
                        .bucket(minioConfig.getCoverBucket())
                        .object(fileName)
                        .stream(inputStream, file.getSize(), -1)
                        .contentType(file.getContentType())
                        .build()
                );
            }

            // 生成预签名URL，有效期7天
            String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(minioConfig.getCoverBucket())
                    .object(fileName)
                    .expiry(7, java.util.concurrent.TimeUnit.DAYS)
                    .build()
            );

            // 返回预签名URL
            return presignedUrl;

        } catch (Exception e) {
            log.error("上传活动封面到MinIO失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    @Override
    public void deleteCover(String fileName) {
        try {
            // 从URL中提取对象名
            String objectName = extractObjectNameFromUrl(fileName);
            
            minioClient.removeObject(
                RemoveObjectArgs.builder()
                    .bucket(minioConfig.getCoverBucket())
                    .object(objectName)
                    .build()
            );
            log.info("成功删除活动封面文件: {}", objectName);
        } catch (Exception e) {
            log.error("删除活动封面文件失败: {}", fileName, e);
        }
    }

    /**
     * 根据文件扩展名获取Content-Type
     */
    private String getContentType(String extension) {
        if (extension == null) {
            return "application/octet-stream";
        }
        
        switch (extension.toLowerCase()) {
            case ".jpg":
            case ".jpeg":
                return "image/jpeg";
            case ".png":
                return "image/png";
            case ".gif":
                return "image/gif";
            case ".bmp":
                return "image/bmp";
            default:
                return "application/octet-stream";
        }
    }

    /**
     * 确保存储桶存在
     */
    private void ensureBucketExists() {
        try {
            boolean bucketExists = minioClient.bucketExists(
                BucketExistsArgs.builder()
                    .bucket(minioConfig.getBucket())
                    .build()
            );

            if (!bucketExists) {
                minioClient.makeBucket(
                    MakeBucketArgs.builder()
                        .bucket(minioConfig.getBucket())
                        .build()
                );
                log.info("创建存储桶: {}", minioConfig.getBucket());
            }
        } catch (Exception e) {
            log.error("检查或创建存储桶失败", e);
            throw new RuntimeException("存储桶操作失败: " + e.getMessage());
        }
    }

    /**
     * 确保封面存储桶存在
     */
    private void ensureCoverBucketExists() {
        try {
            boolean bucketExists = minioClient.bucketExists(
                BucketExistsArgs.builder()
                    .bucket(minioConfig.getCoverBucket())
                    .build()
            );

            if (!bucketExists) {
                minioClient.makeBucket(
                    MakeBucketArgs.builder()
                        .bucket(minioConfig.getCoverBucket())
                        .build()
                );
                log.info("创建封面存储桶: {}", minioConfig.getCoverBucket());
            }
        } catch (Exception e) {
            log.error("检查或创建封面存储桶失败", e);
            throw new RuntimeException("封面存储桶操作失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null) {
            return "";
        }
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0) {
            return filename.substring(lastDotIndex);
        }
        return "";
    }

    /**
     * 从URL中提取对象名
     */
    @Override
    public String extractObjectNameFromUrl(String url) {
        if (url == null || url.isEmpty()) {
            return "";
        }
        
        // 如果URL包含存储桶名称，提取对象名部分
        String bucketPrefix = minioConfig.getEndpoint() + "/" + minioConfig.getBucket() + "/";
        String coverBucketPrefix = minioConfig.getEndpoint() + "/" + minioConfig.getCoverBucket() + "/";
        
        if (url.startsWith(bucketPrefix)) {
            return url.substring(bucketPrefix.length());
        } else if (url.startsWith(coverBucketPrefix)) {
            return url.substring(coverBucketPrefix.length());
        }
        
        // 如果只是对象名，直接返回
        return url;
    }
    
    @Override
    public String generatePresignedUrl(String objectName, String folder) {
        try {
            String bucketName;
            if ("covers".equals(folder)) {
                bucketName = minioConfig.getCoverBucket();
            } else {
                bucketName = minioConfig.getBucket();
            }
            
            // 生成预签名URL，有效期7天
            String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(objectName)
                    .expiry(7, java.util.concurrent.TimeUnit.DAYS)
                    .build()
            );
            
            return presignedUrl;
            
        } catch (Exception e) {
            log.error("生成预签名URL失败: objectName={}, folder={}", objectName, folder, e);
            throw new RuntimeException("生成预签名URL失败: " + e.getMessage());
        }
    }
    
    @Override
    public Resource getFile(String filename, String folder) {
        try {
            String bucketName;
            if ("covers".equals(folder)) {
                bucketName = minioConfig.getCoverBucket();
            } else {
                bucketName = minioConfig.getBucket();
            }
            
            // 生成预签名URL
            String presignedUrl = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(filename)
                    .expiry(1, java.util.concurrent.TimeUnit.HOURS)
                    .build()
            );
            
            // 创建URL资源
            return new UrlResource(presignedUrl);
            
        } catch (Exception e) {
            log.error("获取文件资源失败: filename={}, folder={}", filename, folder, e);
            return null;
        }
    }
} 